package task

import (
	"time"

	"file_explorer/common/log"
)

const (
	StatusInit = iota
	StatusRunning
	StatusPause
	StatusCancel
	StatusFinish
)

type FeTask interface {
	GetLabel() string
	GetProgress() string
	GetPercentage() float64

	Pause()
	Continue()
	Cancel()
	SetOnFinish(callback func(costTime int64, ok bool, err error))
	GetOnFinish() func(costTime int64, ok bool, err error)

	start()
	fail(error)
	finish()
}

type BasicTask struct {
	label      string
	progress   string
	percentage float64
	err        error
	startTime  time.Time
	pauseChan  chan struct{}
	status     int
	onFinish   func(costTime int64, ok bool, err error)
}

func (task *BasicTask) GetLabel() string {
	return task.label
}

func (task *BasicTask) GetProgress() string {
	return task.progress
}

func (task *BasicTask) GetPercentage() float64 {
	return task.percentage
}

func (task *BasicTask) Pause() {
	if task.status != StatusRunning {
		log.Debug("task is not running, label=%v", task.label)
		return
	}
	task.status = StatusPause
	log.Debug("task paused, label=%v", task.label)
}

func (task *BasicTask) Continue() {
	if task.status != StatusPause {
		log.Debug("task is not paused, label=%v", task.label)
		return
	}
	task.status = StatusRunning
	log.Debug("task running, label=%v", task.label)
	task.pauseChan <- struct{}{}
}

func (task *BasicTask) Cancel() {
	if task.status == StatusFinish {
		log.Debug("task has already finished, label=%v", task.label)
		return
	}
	task.status = StatusCancel
	log.Debug("task cancelled, label=%v", task.label)
}

func (task *BasicTask) start() {
	task.startTime = time.Now()
	task.status = StatusRunning
	log.Debug("task started, label=%v", task.label)
}

func (task *BasicTask) isRunning() bool {
	if task.status == StatusPause {
		<-task.pauseChan
	}
	return task.status == StatusRunning && task.err == nil
}

func (task *BasicTask) fail(err error) {
	task.err = err
	log.Error("task failed, label=%v, err=%v", task.label, err)
}

func (task *BasicTask) finish() {
	defer func() {
		task.status = StatusFinish
	}()

	close(task.pauseChan)

	if task.onFinish == nil {
		return
	}
	// 手动取消
	if task.status == StatusCancel {
		task.onFinish(time.Now().Sub(task.startTime).Milliseconds(), false, nil)
		return
	}
	// 正常或异常结束
	task.onFinish(time.Now().Sub(task.startTime).Milliseconds(), task.err == nil, task.err)
}

func (task *BasicTask) SetOnFinish(callback func(costTime int64, ok bool, err error)) {
	task.onFinish = callback
}
func (task *BasicTask) GetOnFinish() func(costTime int64, ok bool, err error) {
	return task.onFinish
}

func newBasicTask(label string) BasicTask {
	return BasicTask{
		label:     label,
		status:    StatusInit,
		pauseChan: make(chan struct{}),
		onFinish:  nil,
	}
}
